package com.dux.commons.xml;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import org.apache.log4j.Logger;

import com.dux.commons.utils.XmlObjectUtil;


/**
 * 加载类（注解配置对象所对应的XML文件路径，并将XML转成对象赋值给相对的对象）
 * @author 杜祥
 * @date 2012-08-21
 */
public class DataHolderProcessor
{
	private static Logger log = Logger.getLogger(DataHolderProcessor.class);
	
	private static String data = "./data/";
	/**
	 * 通过注解找到对象所对象XML，并将文件映射成执行的对象
	 * @param obj	对象
	 */
	@SuppressWarnings("rawtypes")
	public static void process(Object obj)
	{
		Class clazz = null;
		/**判断此对象是否是class**/
		if(obj instanceof Class)
		{
			clazz = (Class) obj;
			obj = null;
		}
		else
		{
			clazz = obj.getClass();
		}
		
		process(clazz,obj);
	}
	
	
	/**
	 * 指定名字的对象通过注解赋值。
	 * @param obj
	 * @param name
	 */
	@SuppressWarnings("rawtypes")
	public static void processName(Object obj, String name)
	{
		Class clazz = null;
		/**判断此对象是否是class**/
		if(obj instanceof Class)
		{
			clazz = (Class) obj;
			obj = null;
		}
		else
		{
			clazz = obj.getClass();
		}
		processName(clazz, obj, name);
	}
	
	
	
	/**
	 * 赋值
	 * @param clazz
	 * @param obj
	 * @param name
	 */
	@SuppressWarnings("rawtypes")
	private static void processName(Class clazz, Object obj, String name)
	{
		try
		{
			Field f = clazz.getDeclaredField(name);
			
			if(Modifier.isStatic(f.getModifiers()) && obj != null)
			{
				return;
			}
			if(!Modifier.isStatic(f.getModifiers()) && obj == null)
			{
				return;
			}
			if(f.isAnnotationPresent(DataHolder.class))
			{
				if(Modifier.isFinal(f.getModifiers()))
				{
					StringBuilder builder = new StringBuilder("对象[");
					builder.append(clazz.getName()).append("]的属性:[").append(f.getName())
					.append("]修饰符有final,所以无法赋值");
					log.error(builder.toString());
					RuntimeException re = new RuntimeException(builder.toString());
					throw re;
				}
				else
				{
					processField(f, obj);
				}
			}
			if(f.isAnnotationPresent(DataHolderFolder.class))
			{
				if(Modifier.isFinal(f.getModifiers()))
				{
					StringBuilder builder = new StringBuilder("对象[");
					builder.append(clazz.getName()).append("]的属性:[").append(f.getName())
					.append("]修饰符有final,所以无法赋值");
					log.error(builder.toString());
					RuntimeException re = new RuntimeException(builder.toString());
					throw re;
				}
				else
				{
					processFolderField(f, obj);
				}
			}
		} 
		catch (Exception e)
		{
			log.error("热加载数据出错,Class[" + clazz.getName() + "]Field[" + name + "].", e);
		}
	}
	
	
	
	
	/**
	 * 将对象赋值（包含对象所标识的类、接口）
	 * @param clazz
	 */
	@SuppressWarnings("rawtypes")
	private static void process(Class clazz, Object obj)
	{
		/**通过Field将对象赋值**/
		processField(clazz, obj);
		if (obj == null)
		{
			/**确定此对象所表示的类或接口实现的接口。**/
			for (Class itf : clazz.getInterfaces())
			{
				process(itf, obj);
			}
		}
		/**Class 所表示的实体（类、接口、基本类型或 void）的超类的 Class赋值**/
		Class superClass = clazz.getSuperclass();
		if(superClass != null && superClass != Object.class)
		{
			process(superClass);
		}
	}
	
	
	
	/**
	 * 通过对象对应域给对象赋值
	 * @param clazz
	 */
	@SuppressWarnings( "rawtypes" )
	private static void processField(Class clazz, Object obj)
	{
		for(Field f : clazz.getDeclaredFields())
		{
			if(Modifier.isStatic(f.getModifiers()) && obj != null)
			{
				continue;
			}
			if(!Modifier.isStatic(f.getModifiers()) && obj == null)
			{
				continue;
			}
			if(f.isAnnotationPresent(DataHolder.class))
			{
				if(Modifier.isFinal(f.getModifiers()))
				{
					StringBuilder builder = new StringBuilder("对象[");
					builder.append(clazz.getName()).append("]的属性:[").append(f.getName())
					.append("]修饰符有final,所以无法赋值");
					log.error(builder.toString());
					RuntimeException re = new RuntimeException(builder.toString());
					throw re;
				}
				else
				{
					processField(f, obj);
				}
			}
			if(f.isAnnotationPresent(DataHolderFolder.class))
			{
				if(Modifier.isFinal(f.getModifiers()))
				{
					StringBuilder builder = new StringBuilder("对象[");
					builder.append(clazz.getName()).append("]的属性:[").append(f.getName())
					.append("]修饰符有final,所以无法赋值");
					log.error(builder.toString());
					RuntimeException re = new RuntimeException(builder.toString());
					throw re;
				}
				else
				{
					processFolderField(f, obj);
				}
			}
		}
	}
	
	/**
	 * 通过域给对象赋值
	 * @param f
	 */
	private static void processField(Field f,Object obj)
	{
		boolean oldAccessible = f.isAccessible();
		
		f.setAccessible(true);
		/**得到域的注解对象**/
		DataHolder dataholder = f.getAnnotation(DataHolder.class);
		/**判断路径是否合法**/
		if(dataholder.name().isEmpty())
		{
			log.warn("DataHolder " + f.getName() + " class " + f.getDeclaringClass().getName() + " leng为0");
		}
		else
		{
			/**判断路径是否存在，并读取该文件**/
			File file = new File(dataholder.name());
			/**如果路径存在，则读取对象**/
			if(file.exists())
			{
				try
				{
					//给域赋值
					f.set(obj, XmlObjectUtil.XmlToJavaBean(file, f.getType()));
				} 
				catch (Exception e) 
				{
					/**如果路径不存在**/
					StringBuilder builder = new StringBuilder("类[").append(f.getDeclaringClass().getName());
					builder.append("]属性[").append(f.getName()).append("]的注解指定的文件[").append(dataholder.name());
					builder.append("]无法转换。");
					log.error(builder.toString(), e);
				}
			}
			else
			{
				/**如果路径不存在**/
				StringBuilder builder = new StringBuilder("类[").append(f.getDeclaringClass().getName());
				builder.append("]属性[").append(f.getName()).append("]的注解指定的文件[").append(dataholder.name());
				builder.append("]不存在。");
				log.warn(builder.toString());
			}
		}
		f.setAccessible(oldAccessible);
	}
	
	
	/**
	 * 
	 * @param f
	 * @param obj
	 */
	private static void processFolderField(Field f,Object obj)
	{
		boolean oldAccessible = f.isAccessible();
		
		f.setAccessible(true);
		/**得到域的注解对象**/
		DataHolderFolder dataholder = f.getAnnotation(DataHolderFolder.class);
		String folderName = null;
		String fileName = null;
		/**判断路径是否合法**/
		if(dataholder.folderName().isEmpty())
			log.warn("DataHolderFolder " + f.getName() + " class " + f.getDeclaringClass().getName() + " leng为0");
		else
			folderName = dataholder.folderName();
		if(dataholder.fileName().isEmpty())
		{
			int index = folderName.lastIndexOf("/");
			if(index == folderName.length() - 1)
			{
				fileName = data + folderName.substring(folderName.lastIndexOf("/", index - 1) + 1, index) + ".xml";
			}
			else
			{
				fileName = data + folderName.substring(index + 1, folderName.length()) + ".xml";
			}
		}
		else
		{
			fileName = dataholder.fileName();
		}
		File file = new File(folderName);
		if(file.exists())
		{
			XMLDataLoader loader = new XMLDataLoader();
			loader.doupdate(folderName, fileName);
			try
			{
				f.set(obj, XmlObjectUtil.XmlToJavaBean(fileName, f.getType()));
			}
			catch (Exception e)
			{
				e.printStackTrace();
			} 
		}
		else
		{
			/**如果路径不存在**/
			StringBuilder builder = new StringBuilder("类[").append(f.getDeclaringClass().getName());
			builder.append("]属性[").append(f.getName()).append("]的注解指定的文件[").append(dataholder.folderName());
			builder.append("]不存在。");
			log.warn(builder.toString());
		}
		f.setAccessible(oldAccessible);
	}
	
	public static void main(String[] args)
	{
		String folderName = "./data/scene";
		int index = folderName.lastIndexOf("/");
		System.out.println(index);
		System.out.println(folderName.substring(index + 1, folderName.length()));
	}
}
